#include <QDebug>
#include "MultiEditor.h"

MultiEditor::MultiEditor(QWidget *parent) : QObject(parent) {
	qDebug() << "[MultiEditor] MultiEditor was created";
	
	firstOpenedEditor = true;
	
	tabWidget = new TabsWidget(parent);
	tabWidget->setTabsClosable(true);
	
	currentEditor = 0;
	previousEditorIndex = -1;
	showTabBarWithOneTab = true;
	showFilesList = true;
	
	connect(tabWidget,SIGNAL(currentChanged(int)),this,SLOT(currentIndexChanged(int)));
	connect(tabWidget,SIGNAL(tabCloseRequested(int)),this,SLOT(closeTabByRequest(int)));
}

MultiEditor::~MultiEditor() {
	for (int i = tabWidget->count()-1; i >= 0; i--)
		closeEditor(i);
	delete tabWidget;
	qDebug() << "[MultiEditor] MultiEditor was destroyed";
}

void MultiEditor::previousEditor() {
	if (tabWidget->count() < 2)
		return;
	int currentIndex = tabWidget->currentIndex();
	if (currentIndex == 0)
		currentIndex = tabWidget->count() - 1;
	else
		currentIndex--;
	tabWidget->setCurrentIndex(currentIndex);
}

void MultiEditor::nextEditor() {
	if (tabWidget->count() < 2)
		return;
	int currentIndex = tabWidget->currentIndex();
	if (currentIndex == tabWidget->count() - 1)
		currentIndex = 0;
	else
		currentIndex++;
	tabWidget->setCurrentIndex(currentIndex);
}

void MultiEditor::addEditor(const QString& tabTitle) {
	QString editorTitle = tabTitle;
	if (editorTitle.isEmpty())
		editorTitle = tr("Untitled");
	
	qDebug() << "[MultiEditor] Add new editor with title" << editorTitle;
	
	Editor *newEditor = new Editor;
	connect(newEditor,SIGNAL(modificationChanged(bool)),this,SLOT(setCurrentEditorModification(bool)));
	connect(newEditor,SIGNAL(contextMenuRequested(int,int)),this,SIGNAL(contextMenuCalled(int,int)));
	connect(newEditor,SIGNAL(changeFileRequested(int)),tabWidget,SLOT(setCurrentIndex(int)));
	connect(newEditor,SIGNAL(filesListStatusChanged(bool)),this,SLOT(showOpenedFilesList(bool)));
	
	if (firstOpenedEditor) {
		currentEolMode = newEditor->eolMode();
		firstOpenedEditor = false;
	}
	
	int newIndex = tabWidget->addTab(newEditor,editorTitle);
	tabWidget->setCurrentIndex(newIndex);
	
	newEditor->setEditorIndex(newIndex);
	newEditor->setFilesListStatus(showFilesList);
	newEditor->setEolMode(currentEolMode);
	
	foreach (Editor *editor,openedEditors) {
		newEditor->addItemToFilesList(tabWidget->indexOf(editor),tabWidget->tabText(tabWidget->indexOf(editor)));
		editor->addItemToFilesList(newIndex,editorTitle);
	}
	
	newEditor->addItemToFilesList(newIndex,editorTitle);
	newEditor->selectItemInFilesList();
	openedEditors << newEditor;
	
	// When user close all tabs current index int tab widget is 0 and 
	// when we create new tab this index is saved, that's why slot currentIndexChanged isn't emitted
	if (tabWidget->count() == 1)
		currentIndexChanged(0);
	
	updateTabsBarStatus();
}

void MultiEditor::closeEditor(int editorIndex) {
	qDebug() << "[MultiEditor] Close editor with index" << editorIndex;
	
	if (editorIndex < 0 && editorIndex >= tabWidget->count())
		return;
	
	foreach (Editor *editor,openedEditors) {
		editor->removeItemFromFilesList(editorIndex);
		editor->reduceIndexOfItemsSince(editorIndex);
		if (editor->getEditorIndex() > editorIndex)
			editor->setEditorIndex(editor->getEditorIndex()-1);
	}

	tabWidget->removeTab(editorIndex);
	delete openedEditors.takeAt(editorIndex);
	if (tabWidget->count() == 0)
		currentEditor = 0;
	
	updateTabsBarStatus();
	
	if (previousEditorIndex != -1) {
		tabWidget->setCurrentIndex(previousEditorIndex);
		previousEditorIndex = -1;
	}
}

void MultiEditor::closeCurrentEditor() {
	closeEditor(tabWidget->currentIndex());
}

Editor* MultiEditor::getEditor(int editorIndex) const {
	if (editorIndex >= 0 && editorIndex < tabWidget->count())
		return openedEditors[editorIndex];
	return 0;
}

Editor* MultiEditor::getCurrentEditor() const {
	return currentEditor;
}

const EditorsList& MultiEditor::getOpenedEditors() const {
	return openedEditors;
}

QTabWidget* MultiEditor::getTabWidget() const {
	return tabWidget;
}

void MultiEditor::currentIndexChanged(int currentIndex) {
	qDebug() << "[MultiEditor] Current index changed on" << currentIndex << "with title" << tabWidget->tabText(currentIndex);
	if (tabWidget->count() > 0) {
		currentEditor = qobject_cast<Editor *>(tabWidget->currentWidget());
		if (currentEditor) {
			currentEditor->setFocus();
			currentEditor->selectItemInFilesList();
		} else
			currentEditor = 0;
		emit (currentTabTextChanged(tabWidget->tabText(currentIndex)));
	} else {
		currentEditor = 0;
		emit (currentTabTextChanged(""));
	}
	emit (currentEditorChanged(currentEditor));
}

void MultiEditor::setEditorModification(int index,bool isModified) {
	if (getEditor(index)->isModified() != isModified)
		getEditor(index)->setModified(isModified);
	QString tabTextBefore = tabWidget->tabText(index).remove("*");
	setTabText(index,isModified ? tabTextBefore + "*" : tabTextBefore);
}

void MultiEditor::setTabText(int index,const QString& text) {
	if (tabWidget->count() > 0) {
		tabWidget->setTabText(index,text);
		if (index == tabWidget->currentIndex())
			emit (currentTabTextChanged(text));
		
		foreach (Editor *editor,openedEditors)
			editor->changeItemTitleInFilesList(index,text);
	}
}

void MultiEditor::setCurrentEditorModification(bool isModified) {
	setEditorModification(getCurrentIndex(),isModified);
}

void MultiEditor::setCurrentTabText(const QString& text) {
	setTabText(getCurrentIndex(),text);
}

void MultiEditor::moveToEditorWithName(const QString& editorName) {
	for (int i = 0; i < tabWidget->count(); i++) {
		if (tabWidget->tabText(i).remove("*") == editorName) {
			tabWidget->setCurrentIndex(i);
			break;
		}
	}
}

void MultiEditor::showTabBarWhenOpenedOneEditor(bool show) {
	showTabBarWithOneTab = show;
}

void MultiEditor::updateTabsBarStatus() {
	if (!areTabsVisible) {
		tabWidget->showTabBar(false);
		return;
	}
	if (tabWidget->count() < 2)
		tabWidget->showTabBar(showTabBarWithOneTab);
	else
		tabWidget->showTabBar(true);
}

void MultiEditor::showOpenedFilesList(bool show) {
	showFilesList = show;
	foreach (Editor *editor,openedEditors)
		editor->setFilesListStatus(show);
}

void MultiEditor::closeTabByRequest(int index) {
	if (index < tabWidget->currentIndex())
		previousEditorIndex = tabWidget->currentIndex() - 1;
	else
		previousEditorIndex = tabWidget->currentIndex();
	tabWidget->setCurrentIndex(index);
	emit(currentTabCloseRequested());
}

int MultiEditor::count() {
	return tabWidget->count();
}

void MultiEditor::openFirstTab() {
	if (tabWidget->count() > 0)
		tabWidget->setCurrentIndex(0);
}

int MultiEditor::getCurrentIndex() {
	return tabWidget->currentIndex();
}

QString MultiEditor::getCurrentTabText() const {
	if (tabWidget->currentIndex() == -1)
		return "";
	return tabWidget->tabText(tabWidget->currentIndex());
}

void MultiEditor::goToLineInCurrentEditor(int line) {
	getCurrentEditor()->moveToLineNumber(line);
}

int MultiEditor::getLinesCountOfCurrentEditor() {
	return getCurrentEditor()->lines();
}

void MultiEditor::undo() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->undo();
}

void MultiEditor::redo() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->redo();
}

void MultiEditor::cut() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->cut();
}

void MultiEditor::copy() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->copy();
}

void MultiEditor::paste() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->paste();
}

void MultiEditor::selectAll() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->selectAll();
}

void MultiEditor::commentSelectedText() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->commentSelectedText();
}

void MultiEditor::unindentSelectedLines() {
	if (getCurrentEditor() != 0)
		getCurrentEditor()->unindentSelectedText();
}

void MultiEditor::setTabsVisible(bool isVisible) {
	areTabsVisible = isVisible;
	updateTabsBarStatus();
}

void MultiEditor::changeEolMode(int modeIndex) {
	qDebug() << "[MultiEditor] Change Eol Mode on" << modeIndex;
	foreach (Editor *editor,openedEditors) {
		if (modeIndex == 0) {
			editor->setEolMode(QsciScintilla::EolUnix);
			currentEolMode = QsciScintilla::EolUnix;
		}
		else if (modeIndex == 1) {
			editor->setEolMode(QsciScintilla::EolWindows);
			currentEolMode = QsciScintilla::EolWindows;
		}
		else if (modeIndex == 2) {
			editor->setEolMode(QsciScintilla::EolMac);
			currentEolMode = QsciScintilla::EolMac;
		}
	}
}
